package geecache

import (
	"fmt"
	"sync"
)

var NOT_EXISTS_VALUE = []byte{0}

type Getter interface {
	Get(key string) ([]byte, error)
}

//使用函数对象来实现接口，是一种很常用的方法
type GetterFunc func(key string) ([]byte, error)

func (f GetterFunc) Get(key string) ([]byte, error) {
	return f(key)
}

type Group struct {
	name      string
	mainCache *cache
	loader    Getter
}

var (
	mu     sync.RWMutex
	groups = make(map[string]*Group)
)

func NewGroup(name string, loadfunc func(name string) ([]byte, error)) (*Group, error) {
	mu.Lock()
	defer mu.Unlock()
	g := &Group{
		name:      name,
		mainCache: &cache{bytes: (1024 * 1024)},
		loader:    GetterFunc(loadfunc),
	}
	groups[name] = g
	return g, nil
}

func GetGroup(name string) (*Group, bool) {
	mu.RLock()
	defer mu.RUnlock()
	if v, ok := groups[name]; ok {
		return v, true
	}
	return nil, false
}

func RemoveGroup(name string) {
	mu.Lock()
	defer mu.Unlock()
	delete(groups, name)
}

func (g *Group) Get(key string) (ByteView, error) {
	if key == "" {
		return ByteView{}, fmt.Errorf("key is nil")
	}
	if v, ok := g.mainCache.get(key); ok {
		return cloneByteView(v), nil
	} else {
		return cloneByteView(g.load(key)), nil
	}
}

func cloneByteView(b ByteView) ByteView {
	//防止缓存击穿
	if len(b.b) == 1 && cap(b.b) == 1 && b.b[0] == 0 {
		return ByteView{}
	}
	//创建一个新的 防止修改缓存值
	r := make([]byte, len(b.b))
	copy(r, b.b)
	return ByteView{r}
}

func (g *Group) Add(key string, bytes []byte) {
	g.mainCache.add(key, ByteView{bytes})
}

func (g *Group) load(key string) ByteView {
	b := ByteView{NOT_EXISTS_VALUE}
	if g.loader != nil {
		if bs, error := g.loader.Get(key); error == nil {
			b = ByteView{bs}
		}
	}
	g.mainCache.add(key, b)
	return b
}
